今天來繼續我們的閉包。
閉包可以在其被定義的上下文中捕獲常量或變量。Swift 中,嵌套函數最簡單捕獲,也就是定義在其他函數裡面的函數。嵌套函數也能捕獲外部函數的參數以及定義的常量和變量。
來看一下官方的例子。
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
makeIncreamenter(forIncrement:) 裡面定義了一個初始值為 0 的變量 runninTotal ,用來儲存總計數值,該值為 incrementer 的返回值。
而 他自己有一個參數值 amount 該參數會被裡面的 incrementer 函數拿來調用並且依照 amount 數值 增加 runningTotal 並將其返回。
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// 返回10
incrementByTen()
// 返回20
incrementByTen()
// 返回30
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// 返回50
上面的例子 incrementByTen 都是常量,但是這些常量指向的閉包還是可以增加裡面的變量值。這是因為函數跟閉包都是引用類型。
顧名思義它能逃出來,但要在前面標註 @escaping 來指名說他是逃逸閉包。
比較常用來做網路請求,因為逃逸閉包會有一個延遲的效果。
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
// 打印出“200”
completionHandlers.first?()
print(instance.x)
// 打印出“100”
逃逸閉包在裡面要顯示的引用 self 而 非逃逸閉包就可以隱式引用 self 差別在逃逸閉包比較容易可能有循環引用,而非逃逸閉包就沒有這個問題。所以通常都會避免太常使用,所以比較常看到在網路請求的部分使用。
OK 今天就到這裡。